use serde::Serialize;
use std::{borrow::Cow, fmt::Display};
use thiserror::Error;

pub type IoErr = std::io::Error;
pub type SqlxErr = sqlx::Error;
pub type ReqErr = reqwest::Error;

#[derive(Debug, Error)]
pub enum AppErr {
    #[error("io:{0}")]
    Io(#[from] IoErr),

    #[error("sqlx:{0}")]
    Sqlx(#[from] SqlxErr),

    #[error("{0}")]
    Custom(Cow<'static, str>),

    #[error("tcp proto:{0}")]
    TcpProto(&'static str),

    #[error("service:{0}")]
    Service(ServiceErr),

    #[error("req:{0}")]
    Req(#[from] ReqErr),
}

#[derive(Debug, Serialize, Error)]
pub struct ServiceErr {
    pub err_code: i32,
    pub err_msg: &'static str,
}

impl Display for ServiceErr {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "ec:{} msg:{}", self.err_code, self.err_msg)
    }
}

pub fn new_err(msg: &'static str) -> AppErr {
    AppErr::Custom(Cow::Borrowed(msg))
}

pub fn new_err_msg(msg: String) -> AppErr {
    AppErr::Custom(Cow::Owned(msg))
}

impl ServiceErr {
    pub fn into_err(self) -> AppErr {
        AppErr::Service(self)
    }
}

pub const SERVICE_NO_TOKEN: ServiceErr = ServiceErr {
    err_code: 1,
    err_msg: "no token",
};

pub const SERVICE_TOKEN_INVALID: ServiceErr = ServiceErr {
    err_code: 2,
    err_msg: "token invalid",
};

pub const SERVICE_NOT_LOGIN: ServiceErr = ServiceErr {
    err_code: 3,
    err_msg: "没有登陆或者登陆超时",
};

pub const SERVICE_NO_USER: ServiceErr = ServiceErr {
    err_code: 4,
    err_msg: "用户不存在",
};

pub const SERVICE_PWD_INVALID: ServiceErr = ServiceErr {
    err_code: 5,
    err_msg: "密码错误",
};

pub const SERVICE_NO_DEVICE: ServiceErr = ServiceErr {
    err_code: 6,
    err_msg: "没有该设备",
};

pub const SERVICE_EXISTS_DEVICE: ServiceErr = ServiceErr {
    err_code: 7,
    err_msg: "设备重复"
};
